package org.vivoweb.harvester.util;
/**
@author Mayank Saini*/
/// Prerequisite Mesaage xml to Undertand the following Class
/**<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://www.bsd.ufl.edu/webservices/IdCard/20100701" elementFormDefault="qualified" targetNamespace="http://www.bsd.ufl.edu/webservices/IdCard/20100701" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="ImageChange">
<xs:sequence>
<xs:element name="DateUpdated" type="xs:dateTime" />
<xs:element name="Image" nillable="true" type="xs:base64Binary" />
<xs:element name="Ufid" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="ImageChange" nillable="true" type="tns:ImageChange" />
</xs:schema>
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.Enumeration;
import java.util.Properties;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.mail.util.ByteArrayDataSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vivoweb.harvester.util.args.ArgDef;
import org.vivoweb.harvester.util.args.ArgList;
import org.vivoweb.harvester.util.args.ArgParser;
import org.vivoweb.harvester.util.args.UsageException;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import sun.misc.BASE64Decoder;
public class ImageQueueConsumer {
/**
* This Class acts a a consumer to image message on the GatorOne publised queue.It
* consumes the message and write it as a Image of specific type. Gator messages are
* of JPEF format
*/
private static Logger log = LoggerFactory.getLogger(ImageQueueConsumer.class);
private static ByteArrayDataSource bytearr;
private static QueueBrowser queueBrowser;
/**
* This is the Image file written in the local dir after consuming the message
*/
private static File file;
private static int browsecount = 0;
/**
* Input steam to the system.property file
*/
private static FileInputStream propFile = null;
/**
* Consumer
* object to consuem the message
*/
private static MessageConsumer consumer;
/**
* UFAD username and password
*/
private static String userName;
private static String password;
private static int maxnum = 1;
private static Properties P = null;
/**
* ActiveMQ Server URL
*/
private static String url;
private static String subject;
private static ConnectionFactory connectionFactory;
private static Connection connection;
private static Session session;
private static Destination destination;
/**
* Dir name to write the Image files
*/
private static String imagedir;
/**
* Dir name to store the property file
*/
private static String propdir;
/**
* Consume all Message from the ActiveMQ queue
* @throws JMSException
*/
public static void getUpdatesFromQueue() throws JMSException {
//this is for testing purpose only.. so that I can test for 5 images at a time
//this need to be changed to while (not all messages ) after the final testing
int failcount = 0;
Message message = null;
if(maxnum == 0)
{
log.info(" Please specify the Non Zero Max count in image.sh");
return;
}
if(maxnum > browsecount)
{
log.info(" Maxfetch count specified is greater then the ActiveMq queue current capacity .");
log.info("Setting Maxfetch to "+browsecount);;
maxnum=browsecount;
}
for(int i = 1; (i <= maxnum); i++) {
if((message = consumer.receive(30000)) == null)
{
failcount++;
continue;
}
processMessage(message);
}
log.info(" End Reading Queue with failcount" + failcount);
}
/**
* This function process the message if message type is ImageChange
* @param JMS Message object
* @throws throws JMSException
*/
public static void processMessage(Message message) throws JMSException {
String jmsType = message.getStringProperty("type");
TextMessage text = (TextMessage)message;
if(text == null)
log.info("No Text Message Found");
else if(jmsType.equals("ImageChange")) {
getUfidsAndImages(text.getText()); // this pacsses the Content of the ImageChange TAG to process
}
}
/**
* This fucntion parsed the XML image
* @param Content of the ImageChange TAG to process
*/
public static void getUfidsAndImages(String xmlText) {
try {
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlText));
Document doc = db.parse(is);
NodeList DateUpdated = doc.getElementsByTagName("DateUpdated");
Element line1 = (Element)DateUpdated.item(0);
String date = getCharacterDataFromElement(line1);
NodeList Image = doc.getElementsByTagName("Image");
Element line2 = (Element)Image.item(0);
String Image_base_64 = getCharacterDataFromElement(line2);
NodeList Ufid = doc.getElementsByTagName("Ufid");
Element line3 = (Element)Ufid.item(0);
String id = getCharacterDataFromElement(line3);
log.info("Uploading Image Uf ID: " + id + "to Dir :" + imagedir);
WriteImageFromBase64(getCharacterDataFromElement(line2), imagedir + id);
log.info("Image Fetched for UFID: " + id + " Uploded Date: " + date);
}
catch(Exception e) {
log.info(e.toString());
}
}
/**
* This function get the XML tag values for example : for Tag "DateUpdated" it will give you the updatedate, for Image Tag it will give
* you the encoded Image String
* @param base64String text encoded Image ,path Path to store the Image,This process repeats for every received message
* @throwsI OException
*/
public static String getCharacterDataFromElement(Element e) {
Node child = e.getFirstChild();
if(child instanceof CharacterData) {
CharacterData cd = (CharacterData)child;
return cd.getData();
}
return "?";
}
/**
* This function convert the base64String encoded image to actual Image and store it in specified directory path
* @param base64String text encoded Image ,path Path to store the Image,This process repeats for every received message
* @throwsI OException
*/
public static void WriteImageFromBase64(String base64String, String path) throws IOException {
BASE64Decoder decoder = new BASE64Decoder();
byte[] buf = decoder.decodeBuffer(base64String);
bytearr = new ByteArrayDataSource(buf, "image/jpeg");
InputStream in = bytearr.getInputStream();
File file = new File(path);
byte buf1[] = new byte[1024];
int len;
FileOutputStream fos = new FileOutputStream(file);
while((len = in.read(buf)) > 0)
fos.write(buf, 0, len);
fos.close();
in.close();
}
/**
* This function create a connection to the activeMQ queue
* @throwsI OException
*/
public static MessageConsumer createConnection() {
connectionFactory = new ActiveMQConnectionFactory(url);
try {
connection = connectionFactory.createConnection(userName, password);
connection.start();
session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);// Auto Ack is on
queueBrowser = session.createBrowser(session.createQueue(subject));
if(queueBrowser == null)
log.info("QueueBrowser: Is null");
else
log.info("QueueBrowser: CREATED");
destination = session.createQueue(subject);
consumer = session.createConsumer(destination);
return consumer;
} catch(JMSException e) {
// TODO Auto-generated catch block
log.info("Connection Failed" + e.toString());
return null;
}
}
/**
* This funtion intialize the class static members { ActiveMQServer,ActiveMQUser,ActiveMQPassword} from the system.properties file
* @throwsI OException
*/
private static void intializeServer() {
file = new File(propdir + "/system.properties");
try {
propFile = new FileInputStream(file);
P = new Properties();
P.load(propFile);
} catch(FileNotFoundException e1) { // TODO Auto-generated catch block
e1.printStackTrace();
} catch(IOException qe) { // TODO Auto-generated catch block
qe.printStackTrace();
}
url = P.getProperty("ActiveMQServer");
userName = P.getProperty("ActiveMQUser");
password = P.getProperty("ActiveMQPassword");
subject = P.getProperty("SUBJECT");
}
public static void main(String... args) throws JMSException {
Exception error = null;
try {
InitLog.initLogger(args, getParser());
log.info(getParser().getAppName() + ": Start");
new ImageQueueConsumer(args).execute();
} catch(IllegalArgumentException e) {
log.error(e.getMessage());
log.debug("Stacktrace:", e);
log.info(getParser().getUsage());
error = e;
} catch(UsageException e) {
log.info("Printing Usage:");
log.info(getParser().getUsage());
error = e;
} catch(Exception e) {
log.error(e.getMessage());
log.debug("Stacktrace:", e);
error = e;
} finally {
log.info(getParser().getAppName() + ": End");
if(error != null) {
System.exit(1);
}
}
}
private static ArgParser getParser() {
ArgParser parser = new ArgParser("ImageQueueConsumer");
parser.addArgument(new ArgDef().setShortOption('p').setLongOpt("pathToImageScriptDirectory").withParameter(true, "PATH").setDescription("path to the Image Script Directory").setRequired(true));
parser.addArgument(new ArgDef().setShortOption('m').setLongOpt("maxFetch").withParameter(true, "MAXFETCH").setDescription("Maximum number if Images that should be fetched from thr queue").setRequired(true));
parser.addArgument(new ArgDef().setShortOption('b').setLongOpt("onlyBrowse").withParameter(true, "onlyBrowse").setDescription("Set this flag to just browse the queue without fetching Images").setRequired(true));
return parser;
}
private String onlyBrowse;
/**
* @throws IOException
*
*/
/**
* Command line Constructor
* @param args command line arguments
* @throws UsageException
* @throws IOException
* @throws IllegalArgumentException
*/
private ImageQueueConsumer(String[] args) throws IllegalArgumentException, IOException, UsageException {
this(getParser().parse(args));
}
public ImageQueueConsumer(String pathToImageDir, String maxFetched, String onlyBrowse) {
maxnum = Integer.parseInt(maxFetched.trim());
this.onlyBrowse = onlyBrowse;
this.propdir = pathToImageDir;
this.imagedir = pathToImageDir + "/images/";
}
/**
* ArgList Constructor
* @param argList option set of parsed args
*/
private ImageQueueConsumer(ArgList argList) {
this(argList.get("p"), argList.get("m"), argList.get("b"));
}
public void execute() throws IOException {
intializeServer();
createConnection();
try {
if(onlyBrowse.equals("yes"))
browseQueue();
else
{
browseQueue();
log.info("getting updates from queue");
getUpdatesFromQueue();
}
connection.close();
} catch(JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
log.info("Pulled Images from Gator one Server");
}
public static void browseQueue() {
try {
Enumeration e = queueBrowser.getEnumeration();
int dotcount = 0;
log.info("Processing Request: ");
while(e.hasMoreElements()) {
e.nextElement();
if((dotcount++ % 50) == 0)
System.out.print(".");
browsecount++;
}
log.info("End");
log.info("Number of Images in the queue: " + browsecount);
} catch(JMSException e) {
log.debug("Error while enumerating!");
}
}
}